﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace PPSkin
{
    [Description("按钮控件"), DefaultEvent("Click")]
    public partial class PPButton : ButtonBase, IButtonControl
    {
        private FrmAnchorTips frmTip;

        #region 定义变量

        private PPAnimation PPAnime;
        private DialogResult myDialogResult;

        private Color baseColor  = Color.White;
        private Color lineColor  = Color.LightGray;
        private Color textColor = Color.Black;

        private Color regularBaseColor = Color.White;
        private Color regularLineColor = Color.LightGray;
        private Color regularTextColor = Color.Black;

        private Color mouseInBaseColor = Color.LightGray;
        private Color mouseInLineColor = Color.Silver;
        private Color mouseInTextColor = Color.Black;

        private Color mouseDownBaseColor = Color.LightGray;
        private Color mouseDownLineColor = Color.Silver;
        private Color mouseDownTextColor = Color.Black;

        private int specialTime = 100;

        private int radius = 3;
        private int lineWidth = 1;
        private int xoffset = 0;
        private int yoffset = 0;
        private int xoffsetIco = 0;
        private int yoffsetIco = 0;
        private Enums.RoundStyle roundStyle = Enums.RoundStyle.All;

        private Image ico = null;
        private Image icoRegular = null;
        private Image icoIn = null;
        private Image icoDown = null;
        private Size icoSize = new Size(15, 15);

        private Align textAlign = Align.CENTER;

        private string text = "";

        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        EditorBrowsable(EditorBrowsableState.Always), Bindable(true)]
        [Description("文本"), Category("PPSkin")]
        public override string Text
        {
            get
            {
                return this.text;
            }
            set
            {
                //if (value == null || value.Length < 1)
                //{
                //    value = this.Name.ToString();
                //}
                this.text = value;
                this.Invalidate();
            }
        }

        [Description("圆角半径"), Category("PPSkin")]
        public int Radius
        {
            get { return radius; }
            set
            {
                radius = value;
                this.Invalidate();
                //this.Region = new Region(PaintHelper.CreateRound(new Rectangle(0, 0, this.Width, this.Height), radius));
            }
        }

        [Description("圆角类型"), Category("PPSkin")]
        public Enums.RoundStyle RoundStyle
        {
            get { return roundStyle; }
            set
            {
                roundStyle = value;
                this.Invalidate();
            }
        }

        [Description("边框宽度,只能是奇数"), Category("PPSkin")]
        public int LineWidth
        {
            get { return lineWidth; }
            set
            {
                lineWidth = value;// % 2 == 0 ? value + 1 : value;
                this.Invalidate();
            }
        }

        [Description("文本x方向偏移量，为正向右，为负向左"), Category("PPSkin")]
        public int Xoffset
        {
            get { return xoffset; }
            set
            {
                xoffset = value;
                this.Invalidate();
            }
        }

        [Description("文本y方向偏移量，为正向下，为负向上"), Category("PPSkin")]
        public int Yoffset
        {
            get { return yoffset; }
            set
            {
                yoffset = value;
                this.Invalidate();
            }
        }

        [Browsable(false)]
        public Color BaseColor
        {
            get { return baseColor; }
            set { 
                baseColor = value;
                this.Invalidate();
            }
        }
        [Browsable(false)]
        public Color LineColor
        {
            get { return lineColor; }
            set
            {
                lineColor = value;
                this.Invalidate();
            }
        }
        [Browsable(false)]
        public Color TextColor
        {
            get { return textColor; }
            set
            {
                textColor = value;
                this.Invalidate();
            }
        }

        [Description("正常背景色"), Category("PPSkin")]
        public Color RegularBaseColor
        {
            get { return regularBaseColor; }
            set
            {
                regularBaseColor = value;
                BaseColor = regularBaseColor;
                this.Invalidate();
            }
        }

        [Description("正常边框色"), Category("PPSkin")]
        public Color RegularLineColor
        {
            get { return regularLineColor; }
            set
            {
                regularLineColor = value;
                LineColor = regularLineColor;
                this.Invalidate();
            }
        }

        [Description("正常文本色"), Category("PPSkin")]
        public Color RegularTextColor
        {
            get { return regularTextColor; }
            set
            {
                regularTextColor = value;
                TextColor = regularTextColor;
                this.Invalidate();
            }
        }

        [Description("鼠标选中背景色"), Category("PPSkin")]
        public Color MouseInBaseColor
        {
            get { return mouseInBaseColor; }
            set
            {
                mouseInBaseColor = value;
                this.Invalidate();
            }
        }

        [Description("鼠标选中边框色"), Category("PPSkin")]
        public Color MouseInLineColor
        {
            get { return mouseInLineColor; }
            set
            {
                mouseInLineColor = value;
                this.Invalidate();
            }
        }

        [Description("鼠标选中文本色"), Category("PPSkin")]
        public Color MouseInTextColor
        {
            get { return mouseInTextColor; }
            set
            {
                mouseInTextColor = value;
                this.Invalidate();
            }
        }

        [Description("鼠标按下背景色"), Category("PPSkin")]
        public Color MouseDownBaseColor
        {
            get { return mouseDownBaseColor; }
            set
            {
                mouseDownBaseColor = value;
                this.Invalidate();
            }
        }

        [Description("鼠标按下边框色"), Category("PPSkin")]
        public Color MouseDownLineColor
        {
            get { return mouseDownLineColor; }
            set
            {
                mouseDownLineColor = value;
                this.Invalidate();
            }
        }

        [Description("鼠标按下文本色"), Category("PPSkin")]
        public Color MouseDownTextColor
        {
            get { return mouseDownTextColor; }
            set
            {
                mouseDownTextColor = value;
                this.Invalidate();
            }
        }

        [Description("正常显示图标"), Category("PPSkin")]
        public Image IcoRegular
        {
            get { return icoRegular; }
            set
            {
                icoRegular = value;
                ico = icoRegular;
                base.Invalidate();
            }
        }

        [Description("鼠标选中图标"), Category("PPSkin")]
        public Image IcoIn
        {
            get { return icoIn; }
            set
            {
                icoIn = value;
                base.Invalidate();
            }
        }

        [Description("鼠标按下图标"), Category("PPSkin")]
        public Image IcoDown
        {
            get { return icoDown; }
            set
            {
                icoDown = value;
                base.Invalidate();
            }
        }

        [Description("图标大小"), Category("PPSkin")]
        public Size IcoSize
        {
            get { return icoSize; }
            set
            {
                icoSize = value;
                base.Invalidate();
            }
        }

        [Description("图标x方向偏移量，为正向下，为负向上"), Category("PPSkin")]
        public int XoffsetIco
        {
            get { return xoffsetIco; }
            set
            {
                xoffsetIco = value;
                base.Invalidate();
            }
        }

        [Description("图标y方向偏移量，为正向下，为负向上"), Category("PPSkin")]
        public int YoffsetIco
        {
            get { return yoffsetIco; }
            set
            {
                yoffsetIco = value;
                base.Invalidate();
            }
        }

        [Description("文字显示位置"), Category("PPSkin")]
        public new Align TextAlign
        {
            get { return textAlign; }
            set
            {
                textAlign = value;
                base.Invalidate();
            }
        }

        [Description("启用动画特效"), Category("PPSkin")]
        public bool UseSpecial { get; set; } = true;

        public enum Align
        {
            LEFT,
            CENTER
        }

        [Description("tip文字"), Category("PPSkin_tip")]
        public string TipText { get; set; }

        [Description("tip文字字体"), Category("PPSkin_tip")]
        public string TipFontText { get; set; }

        [Description("tip字体大小"), Category("PPSkin_tip")]
        public int TipFontSize { get; set; } = 10;

        [Description("tip自动消失时间"), Category("PPSkin_tip")]
        public int TipAutoCloseTime { get; set; } = 5000;

        [Description("tip是否最上"), Category("PPSkin_tip")]
        public bool TipTopMoust { get; set; } = true;

        [Description("tip显示位置"), Category("PPSkin_tip")]
        public AnchorTipsLocation TipLocation { get; set; } = AnchorTipsLocation.TOP;

        [Description("tip背景色"), Category("PPSkin_tip")]
        public Color TipBackColor { get; set; } = Color.DodgerBlue;

        [Description("tip字体色"), Category("PPSkin_tip")]
        public Color TipForeColor { get; set; } = Color.White;

        [Description("tip大小"), Category("PPSkin_tip")]
        public Size TipDeviation { get; set; }

        [Description("tip鼠标移出立即关闭"), Category("PPSkin_tip")]
        public bool TipCloseOnLeave { get; set; } = true;

        public DialogResult DialogResult
        {
            get { return myDialogResult; }
            set
            {
                if (Enum.IsDefined(typeof(DialogResult), value))
                {
                    this.myDialogResult = value;
                }
            }
        }

        #endregion 定义变量

        public Enums.DrawMode TextDrawMode { get; set; } = Enums.DrawMode.Anti;

        public PPButton()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.UpdateStyles();
            //this.Region = new Region(PaintHelper.CreateRound(new Rectangle(0, 0, this.Width, this.Height), radius));
            PPAnime = new PPAnimation(this);
            PPAnime.AnimationRunType = AnimationRunType.Interrupt;
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // PPButton
            // 
            this.Size = new System.Drawing.Size(75, 30);
            this.BackColor = Color.White;
            this.ResumeLayout(false);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                int width = this.Width;
                int height = this.Height;
                int halflinewidth = lineWidth % 2 == 0 ? lineWidth / 2 : lineWidth / 2 + 1;

                Graphics g = e.Graphics;
                g.Clear(BackColor);
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.TextRenderingHint = TextDrawMode == Enums.DrawMode.Anti ? System.Drawing.Text.TextRenderingHint.AntiAlias : System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
                Pen pen = new Pen(LineColor, (float)lineWidth);
                SolidBrush brush = new SolidBrush(BaseColor);
                SolidBrush brush2 = new SolidBrush(TextColor);
                SolidBrush downBrush = new SolidBrush(Color.FromArgb(50, regularBaseColor.A, regularBaseColor.G, regularBaseColor.B));

                GraphicsPath path = PaintHelper.CreatePath(new Rectangle(0, 0, this.Width, this.Height), radius, roundStyle);//PaintHelper.CreateRound(new Rectangle(0, 0, this.Width, this.Height), radius);
                GraphicsPath path2 = PaintHelper.CreatePath(new Rectangle(halflinewidth, halflinewidth, this.Width - lineWidth - 1, this.Height - lineWidth - 1), radius, roundStyle);// PaintHelper.CreateRound(new Rectangle(halflinewidth, halflinewidth, this.Width - lineWidth - 1, this.Height - lineWidth - 1), radius);
                g.FillPath(brush, path2);

                g.DrawPath(pen, path2);
                g.DrawPath(new Pen(this.BackColor), path);
                Size fontsize = TextRenderer.MeasureText(Text, base.Font);

                if (textAlign == Align.CENTER)
                {
                    g.DrawString(Text, base.Font, brush2, new Point(this.Width / 2 - fontsize.Width / 2 + 2 + xoffset, this.Height / 2 - base.Font.Height / 2 + yoffset));
                }
                else
                {
                    g.DrawString(Text, base.Font, brush2, new Point(2 + xoffset, this.Height / 2 - base.Font.Height / 2 + yoffset));
                }

                if (ico != null)
                {
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    g.DrawImage(ico, new Rectangle(new Point(xoffsetIco, yoffsetIco), icoSize));
                }

                pen.Dispose();
                brush.Dispose();
                brush2.Dispose();
                downBrush.Dispose();
                path.Dispose();
                path2.Dispose();
            }
            catch
            { }

            //base.OnPaint(e);
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            if(UseSpecial)
            {
                Dictionary<string, float> dic = new Dictionary<string, float>();
                dic.Add("BaseColor", mouseInBaseColor.ToArgb());
                dic.Add("LineColor", mouseInLineColor.ToArgb());
                dic.Add("TextColor", mouseInTextColor.ToArgb());
                PPAnime.AnimationControl(dic, specialTime);
            }
            else
            {
                BaseColor = mouseInBaseColor;
                LineColor = mouseInLineColor;
                TextColor = mouseInTextColor;
            }

            ico = icoIn;
            this.Invalidate();
            if (TipText != string.Empty)
            {
                frmTip = FrmAnchorTips.ShowTips(this, TipText, TipFontText, TipFontSize, TipAutoCloseTime, TipTopMoust, TipLocation, TipBackColor, TipForeColor, TipDeviation);
            }

            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            if (UseSpecial)
            {
                Dictionary<string, float> dic = new Dictionary<string, float>();
                dic.Add("BaseColor", regularBaseColor.ToArgb());
                dic.Add("LineColor", regularLineColor.ToArgb());
                dic.Add("TextColor", regularTextColor.ToArgb());
                PPAnime.AnimationControl(dic, specialTime);
            }
            else
            {
                BaseColor = regularBaseColor;
                LineColor = regularLineColor;
                TextColor = regularTextColor;
            }

            ico = icoRegular;
            this.Invalidate();
            if (frmTip != null && !frmTip.IsDisposed && TipCloseOnLeave)
            {
                frmTip.Close();
            }

            base.OnMouseLeave(e);
        }

        protected override void OnMouseDown(MouseEventArgs mevent)
        {
            if (UseSpecial)
            {
                Dictionary<string, float> dic = new Dictionary<string, float>();
                dic.Add("BaseColor", mouseDownBaseColor.ToArgb());
                dic.Add("LineColor", mouseDownLineColor.ToArgb());
                dic.Add("TextColor", mouseDownTextColor.ToArgb());
                PPAnime.AnimationControl(dic, specialTime);
            }
            else
            {
                BaseColor = mouseDownBaseColor;
                LineColor = mouseDownLineColor;
                TextColor = mouseDownTextColor;
            }

            ico = icoDown;

            this.Invalidate();
            base.OnMouseDown(mevent);
        }

        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            if (this.Capture)
            {
                if (UseSpecial)
                {
                    Dictionary<string, float> dic = new Dictionary<string, float>();
                    dic.Add("BaseColor", mouseInBaseColor.ToArgb());
                    dic.Add("LineColor", mouseInLineColor.ToArgb());
                    dic.Add("TextColor", mouseInTextColor.ToArgb());
                    PPAnime.AnimationControl(dic, specialTime);
                }
                else
                {
                    BaseColor = mouseInBaseColor;
                    LineColor = mouseInLineColor;
                    TextColor = mouseInTextColor;
                }
                
                ico = icoIn;
            }
            else
            {
                if (UseSpecial)
                {
                    Dictionary<string, float> dic = new Dictionary<string, float>();
                    dic.Add("BaseColor", regularBaseColor.ToArgb());
                    dic.Add("LineColor", regularLineColor.ToArgb());
                    dic.Add("TextColor", regularTextColor.ToArgb());
                    PPAnime.AnimationControl(dic, specialTime);
                }
                else
                {
                    BaseColor = regularBaseColor;
                    LineColor = regularLineColor;
                    TextColor = regularTextColor;
                }
                
                ico = icoRegular;
            }

            this.Invalidate();

            base.OnMouseUp(mevent);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (radius > Math.Min(this.Width, this.Height))
            {
                radius = Math.Min(this.Width, this.Height);
            }
            //this.Region = new Region(PaintHelper.CreateRound(new Rectangle(0, 0, this.Width, this.Height), radius));
        }

        public void NotifyDefault(bool value)
        {
            if (this.IsDefault != value)
            {
                this.IsDefault = value;
            }
        }

        public void PerformClick()
        {
            if (this.CanSelect)
            {
                this.OnClick(EventArgs.Empty);
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if(PPAnime!=null)
            {
                PPAnime.Stop();
                PPAnime.Dispose();
            }
        }
    }
}